home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Sample Code / Graphics Samples / Test Cubics - cubic to quad / TestCubics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-15  |  19.1 KB  |  953 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------------------------
  2. FILENAME
  3.     TestClip.c
  4.     
  5. DESCRIPTION
  6.     This module is used to test that the clipping code works [correctly].  It puts up a window
  7.     and allows the user to enter polygons and to have them clipped.
  8.     
  9. COPYRIGHT
  10.     ©1992 Copyright Apple Computer, Inc.
  11.     All rights reserved.
  12.     
  13. ---------------------------------------------------------------------------------------------*/
  14.  
  15. #include "TestCubics.h"
  16. #include <Strings.h>
  17.  
  18. Cursor gHandCurs;
  19. Boolean gPolyMode;
  20. short        gFileRef;
  21. long        gcount = 0;
  22. long        gticks = 0;
  23.  
  24. long        gpointcount = 0;
  25. long        gquadcount = 0;
  26.  
  27. long        geindx = 2;
  28. extended    gerror = 0.25;
  29.  
  30. short        gcurrent = 0;
  31.  
  32. #pragma segment Main
  33. void main(void)
  34. {
  35.     Initialize();
  36.     EventLoop();
  37. }
  38.  
  39. #pragma segment Main
  40. void EventLoop(void)
  41. {
  42.     Boolean            gotEvent;
  43.     EventRecord     event;
  44.     short            cursFlag;
  45.  
  46.     cursFlag = kCursInit;
  47.     
  48.     do
  49.         {
  50.             SystemTask();
  51.             gotEvent = GetNextEvent(everyEvent,&event);
  52.                 
  53.             if(gotEvent)
  54.                 {
  55.                     AdjustCursor(&event,&cursFlag);
  56.                     DoEvent(&event,&cursFlag);
  57.                 }
  58.             else
  59.                 {
  60.                     AdjustCursor(&event,&cursFlag);
  61.                     /* do Idle stuff */
  62.                 }
  63.         }while(true);
  64. }
  65.  
  66. #pragma segment Main
  67. void DoEvent(EventRecord *event,
  68.                          short *cursFlag)
  69. {
  70.     short         part;
  71.     WindowPtr     window;
  72.     char         key;
  73.     
  74.     switch(event->what)
  75.         {
  76.             case nullEvent:
  77.                 AdjustCursor(event,cursFlag);
  78.                 break;
  79.                 
  80.             case mouseDown:
  81.                 part = FindWindow(event->where,&window);
  82.                 
  83.                 switch(part)
  84.                     {
  85.                         case inMenuBar:
  86.                             AdjustMenus();
  87.                             DoMenuCommand(MenuSelect(event->where));
  88.                             break;
  89.                         
  90.                         case inSysWindow:
  91.                             SystemClick(event,window);
  92.                             break;
  93.                         
  94.                         case inContent:
  95.                             if(window!=FrontWindow())
  96.                                 SelectWindow(window);
  97.                             else
  98.                                 DoContentClick(window,event,cursFlag);
  99.                             break;
  100.                             
  101.                         case inDrag:
  102.                             DragWindow(window,event->where,&qd.screenBits.bounds);
  103.                             break;
  104.                         
  105.                         case inGoAway:
  106.                             if(TrackGoAway(window,event->where))
  107.                                 DoCloseWindow(window);        //  Quit
  108.                             break;
  109.                             
  110.                         case inGrow:
  111.                             DoGrowWindow(window,event);
  112.                             break;
  113.                         
  114.                         case inZoomIn:
  115.                         case inZoomOut:
  116.                             if(TrackBox(window,event->where,part))
  117.                                 DoZoomWindow(window,part);
  118.                             break;
  119.                     }
  120.                 break;
  121.             
  122.             case keyDown:
  123.                 key = event->message & charCodeMask;
  124.                 if(event->modifiers & cmdKey)
  125.                     {
  126.                         AdjustMenus();
  127.                         DoMenuCommand(MenuKey(key));
  128.                     }
  129.                 break;
  130.                 
  131.             case activateEvt:
  132.                 break;
  133.             
  134.             case updateEvt:
  135.                 DoUpdate((WindowPtr) event->message);
  136.                 break;
  137.             
  138.         }
  139. }
  140.  
  141. #pragma segment Main
  142. void AdjustCursor(EventRecord *event,
  143.                                     short *cursFlag)
  144. {
  145.     WindowPtr    window;
  146.     RgnHandle contRgn;
  147.     RgnHandle growRgn;
  148.     Rect            growRect;
  149.     
  150.     window = FrontWindow();
  151.     if(!IsDAWindow(window))
  152.         {
  153.             contRgn = NewRgn();
  154.             growRgn = NewRgn();
  155.             
  156.             if(IsAppWindow(window))
  157.                 {
  158.                     CopyRgn(((WindowPeek)window)->contRgn,contRgn);
  159.                     
  160.                     growRect = (*((WindowPeek)window)->contRgn)->rgnBBox;
  161.                     growRect.top = growRect.bottom - kGrowBHeight;
  162.                     growRect.left = growRect.right - kGrowBWidth;
  163.                     
  164.                     SetPort(window);
  165.                     
  166.                     RectRgn(growRgn,&growRect);
  167.                     
  168.                     SetOrigin(-window->portBits.bounds.left,
  169.                                         -window->portBits.bounds.top);
  170.                     
  171.                     DiffRgn(contRgn,growRgn,contRgn);
  172.                     SetOrigin(0,0);
  173.                 }
  174.                                 
  175.                 if(PtInRgn(event->where,contRgn))
  176.                     {
  177.                         if(event->modifiers & optionKey)
  178.                             {
  179.                                 // do the hand
  180.                                 if(*cursFlag != kCursHand)
  181.                                     {
  182.                                         SetCursor(&gHandCurs);
  183.                                         *cursFlag = kCursHand;
  184.                                     }
  185.                             }
  186.                         else
  187.                             {
  188.                                 if(*cursFlag != kCursCross)
  189.                                     {
  190.                                         SetCursor(*GetCursor(crossCursor));
  191.                                         *cursFlag = kCursCross;
  192.                                     }
  193.                             }
  194.                     }
  195.                 else
  196.                     {
  197.                         SetCursor(&qd.arrow);
  198.                         *cursFlag = kCursArrow;
  199.                     }
  200.                 DisposeRgn(growRgn);
  201.                 DisposeRgn(contRgn);
  202.         }
  203.     else
  204.         {
  205.             if(*cursFlag != kCursArrow)
  206.                 {
  207.                     SetCursor(&qd.arrow);
  208.                     *cursFlag = kCursArrow;
  209.                 }
  210.         }
  211. }
  212. #pragma segment Main
  213. void DoGrowWindow(WindowPtr window,
  214.                                     EventRecord *event)
  215. {
  216.     long        growResult;
  217.     Rect        tempRect;
  218.     DocumentPeek doc;
  219.     
  220.     tempRect = qd.screenBits.bounds;
  221.     tempRect.left = kMinDocSize;
  222.     tempRect.top = kMinDocSize;
  223.     
  224.     growResult = GrowWindow(window, event->where, &tempRect);
  225.  
  226.     if (growResult!=0) 
  227.         {
  228.             doc = (DocumentPeek) window;
  229.             SizeWindow(window, LoWrd(growResult), HiWrd(growResult), true);
  230.             ResizeWindow(window);
  231.     }
  232. }
  233. #pragma segment Main
  234. void DoZoomWindow(WindowPtr window,
  235.                                     short part)
  236. {
  237.     ZoomWindow(window, part, window == FrontWindow());
  238.     ResizeWindow(window);
  239. }
  240.  
  241. #pragma segment Main
  242. void ResizeWindow(WindowPtr window)
  243. {
  244.     InvalRect(&window->portRect);
  245. }
  246.  
  247. #pragma segment Main
  248. void DoUpdate(WindowPtr    window)
  249. {
  250.     if (IsAppWindow(window)) 
  251.         {
  252.             BeginUpdate(window);
  253.             if (! EmptyRgn(window->visRgn))
  254.                 DrawWindow(window);
  255.             EndUpdate(window);
  256.         }
  257. }
  258.  
  259. #pragma segment Main
  260. void DoContentClick(WindowPtr      window,
  261.                                         EventRecord *event,
  262.                                         short                *)
  263. {
  264.     DocumentPeek     doc;
  265.  
  266.     Point        orgPoint;
  267.  
  268.     long        pinVal;
  269.     Rect        pinRect;
  270.     Rect        limitRect;
  271.     
  272.     long        indx;
  273.     
  274.     SetWorkRect(window,&pinRect,&limitRect);
  275.     
  276.     orgPoint = event->where;
  277.     GlobalToLocal(&orgPoint);        // now in local coordinates
  278.         
  279.     pinVal = PinRect(&pinRect,orgPoint);
  280.     orgPoint.h = LoWrd(pinVal);
  281.     orgPoint.v = HiWrd(pinVal);
  282.     
  283.     // convert the gxPoint to fixed gxPoint units and check to see if it
  284.     // is hitting any of the handles off the cubic and re-draw them
  285.     
  286.     doc = (DocumentPeek) window;
  287.     
  288.     // check to see if we have clicked on one of the control points
  289.  
  290.     {
  291.         gxPoint     *dataPtr;
  292.         
  293.         Boolean            found = false;
  294.     
  295.         gcurrent = (-1);            // this is to know if we clicked on nothing
  296.     
  297.         HLockHi((Handle) doc->data );
  298.     
  299.         dataPtr =(gxPoint *) *doc->data;
  300.         
  301.         for( indx = 0; indx < gpointcount; ++indx )
  302.             {                        
  303.                 gcurrent = indx;
  304.  
  305.                 if( DoCubicDrag( dataPtr, orgPoint, doc ) )
  306.                     {            
  307.                         found = true;
  308.                         break;
  309.                     }                
  310.             }
  311.     
  312.         HUnlock((Handle) doc->data );
  313.  
  314.         if( found == false )
  315.             {
  316.                 Handle        dataHdl = (Handle) doc->data;
  317.                                 
  318.                 // ## for now we just add one gxPoint
  319.                 
  320.                 SetHandleSize( dataHdl, ( doc->count + 1 ) * sizeof( gxPoint ) );
  321.                 
  322.                 if( MemError() != noErr ) goto FailedToAddPoint;
  323.                 // now store the gxPoint
  324.                 
  325.                 {
  326.                     gxPoint *dataPtr = & (*(gxPoint **)dataHdl)[ doc->count ];
  327.                     
  328.                     dataPtr->x = ff( orgPoint.h );
  329.                     dataPtr->y = ff( orgPoint.v );
  330.                     
  331.                     DrawControlHandle( dataPtr );
  332.                 }
  333.                 
  334.                 // increase the count
  335.                 
  336.                 doc->count += 1;
  337.                 gpointcount = doc->count;
  338.                 gcurrent = ( ( gpointcount - 1 ) / 3 ) * 3;
  339.  
  340.                 DrawCubicNumbers( doc );
  341.                 
  342.                 // if this makes an entirely new cubic then draw the gxCurve
  343.                 
  344.                 if( ( doc->count == 4 ) || ( ( 4 < doc->count ) && ( ( doc->count - 4 ) % 3 ) == 0 ) )
  345.                     DrawCurves( doc->data );
  346.             }
  347.     }    
  348.  
  349. FailedToAddPoint:;
  350.  
  351. }
  352.     
  353. #pragma segment Main
  354.  
  355. short DoCubicDrag( gxPoint *dataPtr, Point    start, DocumentPeek doc )
  356. {
  357.     gxRectangle        box;
  358.     
  359.     gxPoint        *where;
  360.     
  361.     where = & dataPtr[ gcurrent ];
  362.         
  363.     // first check to see if the start gxPoint is near the handle
  364.     
  365.     box.left = ff( start.h - 2 );
  366.     box.top = ff( start.v - 2 );
  367.     box.right = ff( start.h + 2 );
  368.     box.bottom = ff( start.v + 2 );
  369.     
  370.     if( GXTouchesRectanglePoint( &box, where ) != false )
  371.         {
  372.             gxShape        sh;
  373.             gxShape        sh2;
  374.  
  375.             gxColor        tempcolor;
  376.             gxColor        tempcolor2;
  377.             
  378.             long        cubeindx;
  379.             
  380.             cubeindx = gcurrent & ~0x3;
  381.             
  382.             if( gcurrent <= 0 )
  383.                 cubeindx = 0;
  384.             else
  385.                 cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  386.             
  387.             if( gpointcount < ( cubeindx + 3 ) ) return( false );
  388.             
  389.             tempcolor.space = gxGraySpace;
  390.             tempcolor.element.gray = 0;
  391.             tempcolor.profile = nil;
  392.         
  393.             tempcolor2.space = gxGraySpace;
  394.             tempcolor2.element.gray = 0xFFFF;
  395.             tempcolor2.profile = nil;
  396.         
  397.             EraseRect(& ((WindowPtr)doc)->portRect );
  398.             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  399.             GXDrawShape( sh );
  400.             GXDisposeShape( sh );
  401.  
  402.             do
  403.                 {                    
  404.                     gxPoint        temppoint;
  405.                     gxPoint        savepoint;
  406.                     
  407.                     GXGetViewPortMouse( doc->vp, &temppoint );
  408.                     
  409.                     GXIgnoreGraphicsNotice( color_already_set );
  410.                     GXIgnoreGraphicsNotice( halftone_already_set );
  411.                     
  412.                     if( temppoint != *where )
  413.                         {
  414.                             savepoint = *where;
  415.                             
  416.                             *where = temppoint;
  417.                             
  418.                             // draw the new  cubic in xor mode
  419.                             
  420.                             sh = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh, gxOpenFrameFill );
  421.                             
  422.                             SetShapeFastXorTransfer( sh, &tempcolor2, &tempcolor );
  423.                             
  424.                             // erase the previous cubic by drawing in xor mode
  425.                             
  426.                             *where = savepoint;
  427.                             
  428.                             sh2 = NewCubic((cubic *) &dataPtr[ cubeindx ] ); GXSetShapeFill( sh2, gxOpenFrameFill );
  429.                             SetShapeFastXorTransfer( sh2, &tempcolor, &tempcolor2 );
  430.                             
  431.                             GXDrawShape( sh );            // erase first
  432.                             GXDrawShape( sh2 );            // draw now
  433.  
  434.                             GXDisposeShape( sh );
  435.                             GXDisposeShape( sh2 );
  436.                             
  437.                             *where = temppoint;
  438.                             
  439.                             DrawCubicNumbers( doc );
  440.                         }
  441.                     
  442.                     GXPopGraphicsNotice();
  443.                     GXPopGraphicsNotice();
  444.                                     
  445.                 } while( StillDown() );
  446.  
  447.             InvalRect(& ((WindowPtr)doc)->portRect );
  448.             
  449.             return( true );
  450.         }
  451.     else
  452.         {
  453.             return( false );
  454.         }
  455. }
  456.  
  457. #pragma segment Main
  458. void SetWorkRect(WindowPtr window,
  459.                                  Rect            *pinRect,
  460.                                  Rect            *limitRect)
  461. {
  462.     SetPort(window);
  463.     *limitRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  464.     GlobalToLocal(&TopLeft(*limitRect));
  465.     GlobalToLocal(&BotRight(*limitRect));
  466.     
  467.     *pinRect = *limitRect;
  468.     
  469.     InsetRect(limitRect,-5,-5);
  470.     InsetRect(pinRect,5,5);
  471.     return;
  472. }
  473. #pragma segment Main
  474. void Initialize( void )
  475. {
  476.     Handle                menuBar;
  477.     Ptr                        storage;
  478.     WindowPtr            window;
  479.     DocumentPeek     doc;
  480.     CursHandle        hCurs;
  481.  
  482.     MaxApplZone(); 
  483.     MoreMasters(); MoreMasters(); MoreMasters();
  484.  
  485.     GXEnterGraphics();
  486.  
  487.     SetGraphicsLibraryErrors();
  488.     SetGraphicsLibraryNotices();
  489.  
  490.     InitGraf((Ptr) &qd.thePort);
  491.     InitFonts();
  492.     InitWindows();
  493.     InitMenus();
  494.     TEInit();
  495.     InitDialogs(nil);
  496.     InitCursor();
  497.  
  498.     menuBar = GetNewMBar(rMenuBar);
  499.  
  500.     SetMenuBar(menuBar);
  501.     DisposHandle(menuBar);
  502.     AddResMenu(GetMHandle(mApple), 'DRVR');
  503.     DrawMenuBar();
  504.  
  505.     storage = NewPtr(sizeof( DocumentRecord ));
  506.     
  507.     if ( storage != nil ) 
  508.         {                        
  509.             window = GetNewWindow(rDocWindow, storage, (WindowPtr) -1);
  510.  
  511.             doc = (DocumentPeek) window;
  512.             doc->vp = GXNewWindowViewPort( window );
  513.             
  514.             GXIgnoreGraphicsNotice(transform_already_set);
  515.             SetDefaultViewPort( doc->vp );
  516.             GXPopGraphicsNotice();
  517.             
  518.             // gxInitialize all of the fields that have to do with the document
  519.             
  520.             doc->count = 0;
  521.             doc->data = (gxPoint **) NewHandle( 0 );        // there are no points
  522.             
  523.             ShowWindow(window);
  524.         }
  525.      else
  526.         DisposPtr(storage);            /* get rid of the storage if it is never used */
  527.         
  528.     hCurs = (CursHandle) GetResource('CURS',rHandCurs);
  529.     
  530.     if(hCurs != nil)
  531.         {
  532.             gHandCurs = **hCurs;
  533.             ReleaseResource((Handle) hCurs);
  534.         }
  535.     
  536.     gPolyMode = false;
  537. }
  538. #pragma segment Main
  539. void DrawControlHandle( gxPoint *where )
  540. {
  541.     gxRectangle        box;
  542.     gxShape             sh;
  543.     
  544.     box.left = where->x - ff( 2 );
  545.     box.top = where->y - ff( 2 );
  546.     box.right = where->x + ff( 2 );
  547.     box.bottom = where->y + ff( 2 );
  548.     
  549.     sh = GXNewRectangle( &box );
  550.  
  551.     GXDrawShape( sh );
  552.     GXDisposeShape( sh );
  553. }
  554.  
  555. void DrawCubicNumbers( DocumentPeek doc )
  556. {
  557.  
  558.     Str255    tempstring;
  559.     
  560.     Rect    erasebox = { 0, 0, 26, 170 };
  561.             
  562.     TextFont( geneva );
  563.     TextSize( 9 );
  564.     
  565.     // now calculate the number of quadratics that are needed to approximate this cubic
  566.     
  567.     sprintf( tempstring, "ticks: %d count: %d", gticks, gpointcount );
  568.     
  569.     EraseRect( &erasebox );
  570.     MoveTo( 5, 24 );
  571.     DrawString( c2pstr( tempstring ) );
  572.     
  573.     // we also need to calculate the error for the current cubic
  574.     
  575.     {
  576.         long             cubeindx;
  577.         extended     ax, ay, a, n;
  578.         extended     curveerror;
  579.         
  580.         long            count;
  581.         gxPoint            *dataPtr; 
  582.         
  583.         if( gcurrent <= 0 ) 
  584.             cubeindx = 0;
  585.         else
  586.             cubeindx = ( ( gcurrent - 1 ) / 3 ) * 3;
  587.         
  588.         if( gpointcount < ( cubeindx + 4 ) ) goto NotDoneYet;
  589.         
  590.         dataPtr = *(doc->data);
  591.         dataPtr = & dataPtr[ cubeindx ];
  592.         
  593.         ax = Fix2X( ( dataPtr[ 3 ].x - dataPtr[ 0 ].x ) + 3 * ( dataPtr[ 1 ].x - dataPtr[ 2 ].x ) );
  594.         ay = Fix2X( ( dataPtr[ 3 ].y - dataPtr[ 0 ].y ) + 3 * ( dataPtr[ 1 ].y - dataPtr[ 2 ].y ) );
  595.         
  596.         a = hypot( ax, ay );
  597.         
  598.         n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  599.         count = ceil( n );
  600.         
  601.         curveerror = a / ( 20 * count * count * count );
  602.         
  603.         sprintf( tempstring, "error: %.4lf  quads: %d", curveerror, count );
  604.         MoveTo( 5, 12 );
  605.         DrawString( c2pstr( tempstring ) );
  606.     }
  607. NotDoneYet:;
  608. }
  609.  
  610. void DrawCubicControl( gxShape sh )                // given a cubic it shows where the control points are
  611. {
  612.     short    count;
  613.     short    indx;
  614.     
  615.     fixed        cross[ 11 ];
  616.     gxPoint        where;
  617.     
  618.     gxShape    sh2;
  619.     
  620.     if( GXCountShapeContours( sh ) == 1 )
  621.         {            
  622.             count = GXCountShapePoints( sh, 1 ) - 2;
  623.             
  624.             cross[ 0 ] = 2;
  625.             cross[ 1 ] = 2;
  626.             cross[ 6 ] = 2;
  627.             
  628.             for( indx = 1; 0 < count; --count )
  629.                 {
  630.                     GetShapeIndexPoint( sh, ++indx, &where );
  631.                 
  632.                     cross[ 2 ] = where.x - ff( 3 );
  633.                     cross[ 3 ] = where.y - ff( 3 );
  634.                     cross[ 4 ] = where.x + ff( 3 );
  635.                     cross[ 5 ] = where.y + ff( 3 );
  636.                     cross[ 7 ] = where.x + ff( 3 );
  637.                     cross[ 8 ] = where.y - ff( 3 );
  638.                     cross[ 9 ] = where.x - ff( 3 );
  639.                     cross[ 10 ] = where.y + ff( 3 );
  640.                     
  641.                     sh2 = GXNewPolygons((gxPolygons *) & cross[ 0 ] );
  642.                     GXSetShapeFill( sh2, gxOpenFrameFill );
  643.                     GXDrawShape( sh2 );
  644.                     GXDisposeShape( sh2 );
  645.                 }
  646.         }
  647. }
  648.  
  649. #pragma segment Main
  650. void DrawWindow(WindowPtr window)
  651. {
  652.     DocumentPeek doc;
  653.     PenState    pen;
  654.     
  655.     doc = (DocumentPeek) window;
  656.     
  657.     SetPort(window);
  658.     GetPenState(&pen);
  659.     
  660.     PenNormal();
  661.     EraseRect(&window->portRect);
  662.     
  663.     gticks = TickCount();
  664.     
  665.     DrawCurves( doc->data );
  666.     gticks = TickCount() - gticks;
  667.     
  668.     DrawCubicNumbers( doc );
  669.  
  670.     // we now draw the cubic and its control points
  671.     
  672.     ForeColor(blackColor);
  673.     DrawMyGrow(window);
  674.     
  675.     SetPenState(&pen);
  676.     return;
  677. }
  678.  
  679. void DrawCurves( gxPoint **data )
  680. {
  681.     long         indx;
  682.     gxColor        tempcolor;
  683.     gxShape        sh;
  684.  
  685.     gxPoint        *dataPtr;
  686.  
  687.     tempcolor.space = gxRGBSpace;
  688.     tempcolor.profile = nil;
  689.     tempcolor.element.rgb.red = 0xFFFF;
  690.     tempcolor.element.rgb.green = tempcolor.element.rgb.blue = 0;
  691.  
  692.     HLock((Handle) data );
  693.  
  694.     dataPtr = *data;
  695.  
  696.     for( indx = 4; indx <= gpointcount; indx += 3 )
  697.         {
  698.             cubic *cube = & dataPtr[ indx - 4 ];
  699.             
  700.             sh = NewCubic( cube );     // first draw the reference cubic (in red)
  701.             GXSetShapeFill( sh, gxOpenFrameFill );
  702.             GXSetShapeColor( sh, &tempcolor );
  703.             GXDrawShape( sh );
  704.             GXDisposeShape( sh );
  705.             
  706.             sh = NewCubic2( cube, gcount );  GXSetShapeFill( sh, gxOpenFrameFill );
  707.         
  708.             GXDrawShape( sh );
  709.             DrawCubicControl( sh );
  710.             GXDisposeShape( sh );
  711.  
  712.             DrawControlHandle( &cube->a );
  713.             DrawControlHandle( &cube->b );
  714.             DrawControlHandle( &cube->c );
  715.             DrawControlHandle( &cube->d );
  716.         }
  717.         
  718.     HUnlock((Handle) data );
  719. }
  720.  
  721. #pragma segment Main
  722. void DrawMyGrow(WindowPtr window)
  723. {
  724.     Rect tempRect;
  725.     Rect drawRect;
  726.     PenState pen;
  727.     
  728.     SetPort(window);
  729.     GetPenState(&pen);
  730.     PenNormal();
  731.     
  732.     tempRect = (*((WindowPeek) window)->contRgn)->rgnBBox;
  733.     
  734.     drawRect.top = tempRect.bottom - 16;
  735.     drawRect.left = tempRect.right -16;
  736.     drawRect.bottom = tempRect.bottom;
  737.     drawRect.right = tempRect.right;
  738.     
  739.     GlobalToLocal(&TopLeft(drawRect));
  740.     GlobalToLocal(&BotRight(drawRect));
  741.     
  742.     EraseRect(&drawRect);
  743.     FrameRect(&drawRect);
  744.     
  745.     drawRect.right -= 2;
  746.     drawRect.bottom -= 2;
  747.     drawRect.left += 5;
  748.     drawRect.top += 5;
  749.     
  750.     FrameRect(&drawRect);
  751.     
  752.     drawRect.right -= 4;
  753.     drawRect.bottom -= 4;
  754.     drawRect.top -= 2;
  755.     drawRect.left -= 2;
  756.     
  757.     EraseRect(&drawRect);
  758.     FrameRect(&drawRect);
  759.     
  760.     SetPenState(&pen);
  761.     return;
  762. }
  763.  
  764.  
  765. #pragma segment Main
  766. void AdjustMenus( void )
  767. {
  768.     WindowPtr    window;
  769.     MenuHandle    menu;
  770.     Boolean        undo;
  771.  
  772.     window = FrontWindow();
  773.  
  774.     menu = GetMHandle(mEdit);
  775.     undo = false;
  776.     
  777.     if ( IsDAWindow(window) ) 
  778.         undo = true;
  779.     
  780.     if ( undo )
  781.         {
  782.             EnableItem(menu, iUndo);
  783.             EnableItem(menu, iCut);
  784.             EnableItem(menu, iCopy);
  785.             EnableItem(menu, iPaste);
  786.             EnableItem(menu, iClear);
  787.         }
  788.     else 
  789.         {
  790.             DisableItem(menu, iUndo);
  791.             DisableItem(menu, iCut);
  792.             DisableItem(menu, iCopy);
  793.             DisableItem(menu, iPaste);
  794.             DisableItem(menu, iClear);
  795.         }
  796.         
  797.     return;
  798. }
  799.  
  800. #pragma segment Main
  801. void DoMenuCommand(long menuResult)
  802. {
  803.     short        menuID;             /* the resource ID of the selected menu */
  804.     short        menuItem;           /* the item number of the selected menu */
  805.     short        itemHit;
  806.     Str255        daName;
  807.     short        daRefNum;
  808.     WindowPtr    window;
  809.     
  810.     window = FrontWindow();
  811.     
  812.     menuID = HiWrd(menuResult);    /* use macros for efficiency to... */
  813.     menuItem = LoWrd(menuResult);    /* get menu item number and menu number */
  814.     
  815.     switch ( menuID ) 
  816.         {
  817.             case mApple:
  818.                 switch ( menuItem ) 
  819.                     {
  820.                         case iAbout:
  821.                             itemHit = Alert(rAboutAlert, nil);
  822.                             break;
  823.                         default:
  824.                             GetItem(GetMHandle(mApple), menuItem, daName);
  825.                             daRefNum = OpenDeskAcc(daName);
  826.                             break;
  827.                     }
  828.                 break;
  829.                 
  830.             case mFile:
  831.                 if( menuItem == iOpen )
  832.                     {
  833.                     }
  834.                 else if( menuItem == iQuit )
  835.                     ExitApplication( window );
  836.                 break;
  837.             
  838.             case mEdit:
  839.                 SystemEdit(menuItem-1); 
  840.                 break;
  841.                 
  842.             case mClip:
  843.                 CheckItem( GetMHandle(mClip), gcount + 1, false );
  844.                 CheckItem( GetMHandle(mClip), menuItem, true );
  845.                 gcount = menuItem - 1;
  846.                 InvalRect(&window->portRect);
  847.                 break;
  848.                 
  849.             case mError:
  850.                 {
  851.                     if( menuItem != geindx )
  852.                         {
  853.                             CheckItem( GetMHandle(mError), geindx, false );
  854.                             CheckItem( GetMHandle(mError), menuItem, true );
  855.                             geindx = menuItem;
  856.                             InvalRect(&window->portRect);
  857.                             
  858.                             switch( menuItem )
  859.                                 {
  860.                                     case iOneTenth:
  861.                                         gerror = 0.01;
  862.                                         break;
  863.                                     case iOneQuater:
  864.                                         gerror = 0.25;
  865.                                         break;
  866.                                     case iOneHalf:
  867.                                         gerror = 0.5;
  868.                                         break;
  869.                                     case iThreeQuaters:
  870.                                         gerror = 0.75;
  871.                                         break;
  872.                                     case iOne:
  873.                                         gerror = 1.0;
  874.                                         break;
  875.                                     case iTwo:
  876.                                         gerror = 2.0;
  877.                                         break;
  878.                                     case iFour:
  879.                                         gerror = 4.0;
  880.                                         break;
  881.                                     case iEight:
  882.                                         gerror = 8.0;
  883.                                         break;
  884.                             }
  885.                     }
  886.                 }
  887.                 break;
  888.     }
  889.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  890. }
  891.  
  892. #pragma segment Main
  893. void DoCloseWindow(WindowPtr window)
  894. {
  895.     if ( IsDAWindow(window) )
  896.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  897.     else if ( IsAppWindow(window) ) 
  898.         ExitApplication( window );    
  899. }
  900.  
  901. #pragma segment Main
  902. Boolean IsAppWindow(WindowPtr window)
  903. {
  904.     short        windowKind;
  905.     
  906.     if ( window == nil )
  907.         return false;
  908.     else {    /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
  909.         windowKind = ((WindowPeek) window)->windowKind;
  910.         return (windowKind >= userKind) || (windowKind == dialogKind);
  911.     }
  912. }
  913.  
  914. #pragma segment Main
  915. Boolean IsDAWindow(WindowPtr    window)
  916. {
  917.     if ( window == nil )
  918.         return false;
  919.     else    /* DA windows have negative windowKinds */
  920.         return ((WindowPeek) window)->windowKind < 0;
  921. }
  922.  
  923.  
  924. void ExitApplication( WindowPtr window )
  925. {    
  926.     DisposeWindow( window );
  927.     GXExitGraphics();
  928.     ExitToShell();
  929. }
  930.  
  931. long CountQuadratics( const cubic *cube )
  932. {
  933.     long            count;
  934.     extended    a, n;
  935.     
  936.     extended ax;
  937.     extended ay;
  938.     
  939.     ax = Fix2X( - cube->a.x + 3 * cube->b.x - 3 * cube->c.x + cube->d.x );
  940.     ay = Fix2X( - cube->a.y + 3 * cube->b.y - 3 * cube->c.y + cube->d.y );
  941.     
  942.     a = hypot( ax, ay );
  943.     
  944.     n = power( ( a / ( 20.0 * gerror ) ), 1.0 / 3.0 );
  945.  
  946.     count = ceil( n );
  947.  
  948.     if( count <= 0 ) 
  949.         count += 1;
  950.  
  951.     return( count );
  952. }
  953.